package org.example.project.common.web.web;


import org.example.project.common.web.contant.R;
import org.example.project.common.web.error.MessageEnum;
import org.example.project.common.web.error.enums.ErrorCode;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

/**
 * rest crud controller for single table
 * <p>
 * 参考Java开发手册前后端规约：
 * <p>
 * 1. 【强制】前后端交互的 API,需要明确协议、域名、路径、请求方法、请求内容、状态码、响应体。
 * 说明:
 * ××1) 协议:生产环境必须使用 HTTPS。
 * 2) 路径:每一个 API 需对应一个路径,表示 API 具体的请求地址:
 * a) 代表一种资源,只能为名词,推荐使用复数,不能为动词,请求方法已经表达动作意义。
 * ××b) URL 路径不能使用大写,单词如果需要分隔,统一使用下划线。
 * c) 路径禁止携带表示请求内容类型的后缀,比如".json",".xml",通过 accept 头表达即可。
 * 3) 请求方法:对具体操作的定义,常见的请求方法如下:
 * a) GET:从服务器取出资源。
 * b) POST:在服务器新建一个资源。
 * c) PUT:在服务器更新资源。
 * d) DELETE:从服务器删除资源。
 * 4) 请求内容: URL 带的参数必须无敏感信息或符合安全要求; body 里带参数时必须设置 Content-Type。
 * 5) 响应体:响应体 body 可放置多种数据类型,由 Content-Type 头来确定。
 * <p>
 * <p>
 * 2. 【强制】前后端数据列表相关的接口返回,如果为空,则返回空数组[]或空集合{}
 * 3. 【强制】服务端发生错误时,返回给前端的响应信息必须包含 HTTP 状态码,errorCode、errorMessage、用户提示信息四个部分。
 * 4. 【强制】在前后端交互的 JSON 格式数据中,所有的 key 必须为小写字母开始的lowerCamelCase 风格,符合英文表达习惯,且表意完整。
 * 5. 【强制】对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用Long 类型
 * 6. 【推荐】服务端返回的数据,使用 JSON 格式而非 XML
 * 7. 【推荐】前后端的时间格式统一为"yyyy-MM-dd HH:mm:ss",统一为 GMT
 * 8. 【参考】在接口路径中不要加入版本号,版本控制在 HTTP 头信息中体现,有利于向前兼容
 *
 * @author wenxy
 * @date 2020/9/28
 */
public interface RestCrudController<DTO, ID> {
    /**
     * save dto
     *
     * @param dto data transform object
     * @return R<RCodeEnum.SUCCESS>
     */
    default ResponseEntity<R<String>> save(DTO dto) {
        return ResponseEntity.ok(R.success());
    }

    /**
     * removeDtoById
     *
     * @param id identifier
     * @return
     * @see R
     */
    default ResponseEntity<R<String>> removeById(ID id) {
        return ResponseEntity.ok(R.success());
    }

    /**
     * getDtoById
     *
     * @param id identifier
     * @return R<DTO>
     * @see R
     */
    ResponseEntity<R<DTO>> getById(ID id);

    /**
     * updateDtoById
     *
     * @param dto data transform object
     * @param id  identifier
     * @return R<RCodeEnum.SUCCESS>
     * @see R
     */
    default ResponseEntity<R<String>> updateById(DTO dto, ID id) {
        return ResponseEntity.ok(R.success());
    }

    /**
     * simple success operation
     * <p>
     * {"resCode":"R0000000","resMsg":"操作成功","data":[],"success":true}
     * {"status":200}
     *
     * @return R<RCodeEnum.SUCCESS>
     * @see R
     */
    default ResponseEntity<R<String>> success() {
        return success(null);
    }

    /**
     * success operation with data
     * <p>
     * {"resCode":"00000","resMsg":"操作成功！","data":[],"success":true}
     * {"status":200}
     *
     * @param data data (common for dto & dtoList)
     * @return R<T>
     * @see R
     */
    default <T> ResponseEntity<R<T>> success(T data) {
        return ResponseEntity.ok(R.success(data));
    }

    /**
     * server fail
     * {"resCode":"B0001","resMsg":"系统执行出错","data":[],"success":false}
     * {"status":500}
     *
     * @return R<ErrorCode.B0001>
     * @see R
     * @see ErrorCode B0001
     */
    default ResponseEntity<R<String>> fail() {
        return ResponseEntity.badRequest().body(R.fail(ErrorCode.B0001));
    }

    /**
     * client fail
     * {"resCode":"A0001","resMsg":"用户端错误","data":[],"success":false}
     * {"status":400}
     *
     * @param messageEnum errorCode
     * @return R<ErrorCode.A0001>
     * @see R
     * @see ErrorCode A0001
     */
    default ResponseEntity<R<String>> fail(MessageEnum messageEnum) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.fail(ErrorCode.A0001));
    }
}
